// /////////////////////////////////////////////////////////////////////////////
//
// Name:            ImageComponent.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           Component wrapper for drawing 2d images.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "ImageComponent.h"
#include "../../core/GameManager.h"


// ImageComponent class
// ImageComponent constructor (default)
ImageComponent::ImageComponent(Entity *parent)
: EntityComponent(parent), mTexture(NULL), mPosition(vector2di(0, 0)),
 mSourceRect(rect<s32>(0, 0, 0, 0)), mClipRect(rect<s32>(0, 0, 0, 0)),
 mColor(SColor(255, 255, 255, 255)), mAlphaColor(SColor(255, 255, 255, 255)), mVisible(true),
 mUseAlphaColor(false)
{
    if(pParent != NULL)
      init();
}

// ImageComponent constructor.
ImageComponent::ImageComponent(Entity *parent, const std::string &fileName,
                               const vector2di &position, const rect<s32> &sourceRect,
                               const rect<s32> &clipRect, const SColor &color,
                               const SColor &alphaColor, bool useAlphaColor)
: EntityComponent(parent), mTexture(NULL), mPosition(position), mSourceRect(sourceRect),
  mClipRect(clipRect), mColor(color), mAlphaColor(alphaColor), mVisible(true),
  mUseAlphaColor(useAlphaColor)
{
    if(pParent != NULL)
    {
       init();
       setTexture(fileName);
    }
}

// ImageComponent constructor.
ImageComponent::ImageComponent(Entity *parent, ITexture *texture,
                               const vector2di &position, const rect<s32> &sourceRect,
                               const rect<s32> &clipRect, const SColor &color,
                               const SColor &alphaColor, bool useAlphaColor)
: EntityComponent(parent), mTexture(NULL), mPosition(position), mSourceRect(sourceRect),
  mClipRect(clipRect), mColor(color), mAlphaColor(alphaColor), mVisible(true),
  mUseAlphaColor(useAlphaColor)
{
    if(pParent != NULL)
    {
       init();
       setTexture(texture);
    }
}


// ImageComponent deconstructor.
ImageComponent::~ImageComponent()
{
    if(mTexture)
      mTexture->drop();
}

// Common initialisation method.
void ImageComponent::init()
{
    // Set misc. variables.
    mName = "ImageComponent";

	// Register events.
	pParent->connectEventSignal("onRender", this, &ImageComponent::onRender);
	pParent->connectEventSignal("onPause", this, &ImageComponent::onPause);
	pParent->connectEventSignal("onUnPause", this, &ImageComponent::onUnPause);
}

// Gets the alpha color.
const SColor& ImageComponent::getAlphaColor() const
{
    return mAlphaColor;
}

// Gets the clipping rectangle.
const rect<s32>& ImageComponent::getClipRect() const
{
    return mClipRect;
}

// Gets the color with which the image is drawn.
const SColor& ImageComponent::getColor() const
{
    return mColor;
}

// Gets the upper left 2d screen position where the image will be drawn.
const vector2di& ImageComponent::getPosition() const
{
    return mPosition;
}

// Gets the source rectangle in the image
const rect<s32>& ImageComponent::getSourceRect() const
{
    return mSourceRect;
}

// Gets the texture associated with this component.
const ITexture* ImageComponent::getTexture() const
{
    return mTexture;
}

// Returns whether the alpha color is used.
bool ImageComponent::getUseAlphaColor() const
{
    return mUseAlphaColor;
}

// Sets the alpha color of the image.
void ImageComponent::setAlphaColor(const SColor &color)
{
    if(mTexture)
      GameManager::Instance()->getDriver()->makeColorKeyTexture(mTexture, color);

    mAlphaColor = color;
}

// Sets where the image is clipped to.
void ImageComponent::setClipRect(const rect<s32> &rectangle)
{
    mClipRect = rectangle;
}

// Sets the color with which the image is drawn.
void ImageComponent::setColor(const SColor &color)
{
    mColor = color;
}

// Sets the upper left 2d screen position where the image will be drawn.
void ImageComponent::setPosition(const vector2di &position)
{
    mPosition = position;
}

// Sets the source rectangle in the image
void ImageComponent::setSourceRect(const rect<s32> &rectangle)
{
    mSourceRect = rectangle;
}

// Loads a texture from the given file and sets it as the texture to be drawn.
void ImageComponent::setTexture(const std::string &fileName)
{
    // Drop reference to previous texture.
    if(mTexture)
      mTexture->drop();

    // Set up variables.
	AssetGroup *assets = pParent->getAssetGroup();
    ITexture *texture = 0;

    // Retrieve pointer to the texture.
    if(assets != NULL)
    {
        // Unsubscribe from previous asset.
        assets->disconnectEventSignal(std::string("textures/") + mTextureFileName, this);

        // Get texture.
        TextureProcessor *processor = static_cast<TextureProcessor*>
                                      (assets->getAssetProcessor("textures"));
        texture = processor->getTexture(fileName);

        if(texture)
        {
           assets->connectEventSignal(std::string("textures/") + fileName, this,
                                        &ImageComponent::onTexture);
           mTextureFileName = fileName;
        }
    }

    else
      texture = GameManager::Instance()->getDriver()->getTexture(fileName.c_str());

    // Set texture.
    mTexture = texture;

    if(mTexture)
    {
       GameManager::Instance()->getDriver()->makeColorKeyTexture(mTexture, mAlphaColor);
       mTexture->grab();
    }
}

// Sets the texture which should be drawn.
void ImageComponent::setTexture(ITexture *texture)
{
    // Drop reference to previous texture.
    if(mTexture)
      mTexture->drop();

    // Check if we need to unsubscribe from an asset group texture.
    AssetGroup *assets = pParent->getAssetGroup();

    if(assets != NULL)
    {
       assets->disconnectEventSignal(std::string("textures/") + mTextureFileName, this);
       mTextureFileName = "";
    }

    // Set texture.
    mTexture = texture;

    if(mTexture)
    {
       GameManager::Instance()->getDriver()->makeColorKeyTexture(mTexture, mAlphaColor);
       mTexture->grab();
    }
}

// Sets whether the alpha color should be used.
void ImageComponent::setUseAlphaColor(bool value)
{
    mUseAlphaColor = value;
}


// Event functions
// Updates the component if the parent is rendered.
void ImageComponent::onRender(void *p)
{
    if(mTexture && mVisible)
    {
       IVideoDriver *driver = GameManager::Instance()->getDriver();
       driver->draw2DImage(mTexture, mPosition, mSourceRect, &mClipRect, mColor, mUseAlphaColor);
    }
}

// Pauses the component if the parent is paused.
void ImageComponent::onPause(void *p)
{
    mWasVisible = mVisible;
}

// Unpauses the component if the parent is unpaused.
void ImageComponent::onUnPause(void *p)
{
    mVisible = mWasVisible;
}

// Responds to changes of the texture attached to this component.
void ImageComponent::onTexture(void *p)
{
    // Get pointer to the new texture.
    ITexture *texture = reinterpret_cast<ITexture*>(p);

    // Drop reference to previous texture.
    if(mTexture)  // Technically unneeded, but rather safe than sorry.
      mTexture->drop();

    // Set new texture.
    mTexture = texture;

    // Get reference to the new texture.
    if(mTexture)
      mTexture->grab();
}

// Serializes this object.
bool ImageComponent::onSerialization(SerializedAttributes *attributes)
{
    // Create a root.
    SerializedAttributes *root = new SerializedAttributes();

    // Serialize attributes.
    root->pushColor("alphaColor", getAlphaColor());
    root->pushRect("clipRect", getClipRect());
    root->pushColor("color", getColor());
    root->pushVector2di("position", getPosition());
    root->pushRect("sourceRect", getSourceRect());
    root->pushString("texture", mTextureFileName);
    root->pushBool("useAlphaColor", getUseAlphaColor());

    // Add root to the given collection of attributes.
    attributes->pushObject("ImageComponent", root);
    root->drop();

    // Return
    return true;
}

// Deserializes this object.
bool ImageComponent::onDeserialization(SerializedAttributes *attributes)
{
    // Retrieve root attribute from the collection.
    SerializedAttribute *rootAttribute = attributes->pullAttribute();

    if(rootAttribute == NULL || rootAttribute->getName() != "ImageComponent")
      return false;

    SerializedAttributes *root = reinterpret_cast<SerializedAttributes*>(rootAttribute->getObject());
    root->grab();

    rootAttribute->drop(); // We no longer need this attribute.

    // Process all attributes in the root collection.
    for(SerializedAttribute *attribute = root->pullAttribute(); attribute != NULL; attribute = root->pullAttribute())
    {
       // Deserialize attributes
            if(attribute->getName() == "alphaColor")      setAlphaColor(attribute->getColor());
       else if(attribute->getName() == "clipRect")        setClipRect(attribute->getRect());
       else if(attribute->getName() == "color")           setColor(attribute->getColor());
       else if(attribute->getName() == "position")        setPosition(attribute->getVector2di());
       else if(attribute->getName() == "sourceRect")      setSourceRect(attribute->getRect());
       else if(attribute->getName() == "texture")         setTexture(attribute->getString());
       else if(attribute->getName() == "useAlphaColor")   setUseAlphaColor(attribute->getBool());

       // We no longer need a reference to the attribute.
       attribute->drop();
    }

    // We no longer need a reference to the root.
    root->drop();

    // We're done.
    return true;
}

// End of File
